/**
 * Copyright &copy; 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved.
 */
package com.jeeplus.modules.web.service;

import java.lang.reflect.InvocationTargetException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;

import com.jeeplus.modules.web.entity.*;
import org.apache.commons.beanutils.BeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.jeeplus.common.utils.StringUtils;
import com.jeeplus.core.persistence.Page;
import com.jeeplus.core.service.CrudService;
import com.jeeplus.modules.monitor.utils.Achieve;
import com.jeeplus.modules.web.entity.wx.YsUser;
import com.jeeplus.modules.web.mapper.WxAgentsMapper;
import com.jeeplus.modules.web.mapper.WxOrderMapper;
import com.jeeplus.modules.web.mapper.WxUserIntegrationRecordMapper;
import com.jeeplus.modules.web.mapper.WxUserMapper;
import com.jeeplus.modules.web.mapper.WxUserWalletMapper;
import com.jeeplus.modules.web.mapper.YjEquipmentMapper;

import net.sf.json.JSONObject;

/**
 * 订单管理Service
 *
 * @author rongjie
 * @version 2017-08-06
 */
@Service
@Transactional(readOnly = true)
public class WxOrderService extends CrudService<WxOrderMapper, WxOrder> {

	@Autowired
	private WxUserMapper wxUserMapper;

	@Autowired
	private WxAgentsMapper agentsMapper;

	@Autowired
	WxUserIntegrationRecordMapper wxUserIntegrationRecordMapper;

	@Autowired
	YjEquipmentMapper yjEquipmentMapper;

	@Autowired
	WxUserWalletService wxUserWalletService;
	@Autowired
	private WxCombinationService wxCombinationService;

	@Autowired
	WxOrderMapper wxOrderMapper;
	private static final int MINUTES_OF_HOUR = 60; // 小时与分钟转换
	private static final int MILLS_OF_SECOND = 1000; // 秒与毫秒转换
	private static final int SECONDS_OF_MINUTE = 60; // 分与秒转换
	private static final Logger log = LoggerFactory.getLogger(WxOrderService.class);

	public WxOrder get(String id) {
		return super.get(id);
	}

	public List<WxOrder> findList(WxOrder wxOrder) {
		return super.findList(wxOrder);
	}

	public Page<WxOrder> findPage(Page<WxOrder> page, WxOrder wxOrder) {
		page = super.findPage(page, wxOrder);
		List<WxOrder> wxOrders = page.getList();
		if (wxOrders != null && wxOrders.size() > 0) {
			List<WxOrder> data = new ArrayList<>();
			wxOrders.forEach(tar -> {
				WxOrder tag = new WxOrder();
				try {
					BeanUtils.copyProperties(tag, tar);
				} catch (IllegalAccessException | InvocationTargetException e) {
					e.printStackTrace();
				}
				tag.setUser(wxUserMapper.get(tag.getUser().getId()));
				if (tag.getEquipment() != null) {
					tag.setAgents(agentsMapper.getAgentsByEquipment(tag.getEquipment().getNumber()));
				}
				data.add(tag);
			});
			page.setList(data);
		}
		return page;
	}

	@Transactional(readOnly = false)
	public void save(WxOrder wxOrder) {
		super.save(wxOrder);
	}

	@Transactional(readOnly = false)
	public void delete(WxOrder wxOrder) {
		super.delete(wxOrder);
	}

	@Transactional(readOnly = false)
	public Map<String, Object> updateOrder(String equipment,String number, String text) {
		WxOrder order = wxOrderMapper.getOrder(number);
		if(order.getType().equals("5")){
			wxOrderMapper.setOrder(number, "", 4, "", "");// 标记订单状态
			yjEquipmentMapper.setLightStatus(equipment, 5);// 设置设备开关灯状态
			// 通过orderNumber匹配命令表，标记已经处理的命令，如果用mac，可能与开机命令混淆
			yjEquipmentMapper.setTypeByOrderNumber(number);
		}else{
			if(order.getStatus().equals("1")){
                //获取设备订单状态
                YjEquipment yjEquipment = yjEquipmentMapper.findUniqueByProperty("number", equipment);
				int orderTime = Integer.parseInt(order.getOrderTime());
				//判断是否运行中
//                List<WxOrder> wxOrderList = wxOrderMapper.getOrderByStatus(equipment, 2).stream().filter(o -> !o.getOrderNumber().equals(number)).collect(Collectors.toList());
//                if(wxOrderList.size() > 0 && yjEquipment.getEndTime()!=null){
//                    //代表有订单运行中，修改结束时间
//                    long endTime = yjEquipment.getEndTime().getTime()+ orderTime*60*1000;
//                    yjEquipment.setEndTime(new Date(endTime));
//					yjEquipment.setOrders(yjEquipment.getOrders()+","+order.getId());
//				}else{
//                    //没有订单运行说明是第一个订单，修改开始时间和结束时间
//                    yjEquipment.setStartTime(order.getTime());
//                    yjEquipment.setEndTime(order.getEndTime());
//					yjEquipment.setOrders(order.getId());
//                }
                yjEquipmentMapper.setTotal(equipment, orderTime,yjEquipment.getStartTime(),yjEquipment.getEndTime(),yjEquipment.getOrders());// 更新yj_equipment表的同时，set_time字段会更新，作为机器最近的心跳响应时间
                yjEquipmentMapper.addRecording(number, equipment, orderTime);
                wxOrderMapper.setOrder(number, "", 2, text, "");
				//
			}else{
				wxOrderMapper.setOrder(number, "", Integer.parseInt(order.getStatus()), text, "");
			}
			// 命令已经处理
			yjEquipmentMapper.setType(equipment);
		}


		Map<String, Object> map = new HashMap<String, Object>();
		map.put("data", "success");
		map.put("code", 0);

		return map;
	}

	@Transactional(readOnly = false)
	public Map<String, Object> returnOrder(String number,String state) {
		WxOrder wxOrder = wxOrderMapper.getOrder(number);
		Double money = Double.valueOf(wxOrder.getOrderMoney());
		// 异常开机退款并扣减积分
		wxUserWalletService.setAddMoney(String.valueOf(money), String.valueOf(money), number,"异常开机退款");
		wxUserWalletService.setIntegration(wxOrder.getUser().getId(), money.intValue());

		// 增加积分明细
		WxUserIntegrationRecord wxUserIntegrationRecords = new WxUserIntegrationRecord();
		WxUser user = new WxUser();
		user.setId(wxOrder.getUser().getId());
		wxUserIntegrationRecords.setUser(user);
		wxUserIntegrationRecords.setType(0);
		wxUserIntegrationRecords.setText("退款扣减");
		wxUserIntegrationRecords.setIntegration(String.valueOf(-money.intValue()));
		wxUserIntegrationRecordMapper.insert(wxUserIntegrationRecords);
		String orderNumber = Achieve.getUUIDString();
		wxOrderMapper.addOrder(orderNumber, wxOrder.getUser().getId(),
				number + "订单剩余时长退款 TimersTask.getRefunds", "4", number + " 订单剩余时长退款 TimersTask.getRefunds",
				String.valueOf(money), "0", null, 0, new Date(),new Timestamp(System.currentTimeMillis()), 0.0, "0");
		wxOrderMapper.setOrder(number, "", 3, state, "异常开机 已退款 详情请查看退款详细订单号:" + orderNumber);
		wxOrderMapper.setOrder(orderNumber, null, 4, state, "异常开机,已退款 开机订单为:" + number);
		yjEquipmentMapper.setType(wxOrder.getEquipment().getNumber());
		yjEquipmentMapper.setLightStatus(wxOrder.getEquipment().getNumber(), -5);// 关灯
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("data", "success");
		map.put("code", 0);

		return map;
	}


	@Transactional(readOnly = false)
	public Map<String, Object> downOrder(YsUser wxUserInfo, HttpServletRequest request) {
		String name = request.getParameter("name"); // 定单备注
		String type = request.getParameter("type"); // 定单title
		String text = request.getParameter("text"); // 定单简短内容介绍
		String number = request.getParameter("number"); // 定单ID（对应与续费业务）
		Double money = request.getParameter("money") == null ? 1 : Double.valueOf(request.getParameter("money")); // 金额
		String coupon = request.getParameter("coupon") == null ? null : request.getParameter("coupon"); // 代金券ID
		Double hourMoney = money;
		String combinationId = request.getParameter("combinationId");


		log.info("======》" + wxUserInfo.getUserName() + " 请求add_order,请求参数:"
				+ com.alibaba.fastjson.JSONObject.toJSONString(request.getParameterMap()));


		String equipment = request.getParameter("equipment"); // 设备号

		Map<String, Object> map = new HashMap<String, Object>();
		Map<String, Object> maps = new HashMap<String, Object>();
		String orderNumber = Achieve.getUUIDString();

		//检测是否有运行中订单
		List<WxOrder> wxOrderList = wxOrderMapper.getOrderByStatus(equipment,1);
		if(wxOrderList.size() > 0){
			map.put("data", "有订单正在开机中，请稍后再试");
			map.put("code", 2);
			return map;
		}

		Integer hour = 0;
		if(StringUtils.isNotBlank(combinationId)){
			WxCombination wxCombination = wxCombinationService.get(combinationId);
			WxAgents agents = yjEquipmentMapper.getAgents(equipment);
            List<WxCombination> wxCombinationList = wxCombinationService.findWxCombination(agents.getId(), wxCombination.getType());
            if(wxCombination!=null && wxCombinationList.size() >0){
                List<String> combinationIds = wxCombinationList.stream().map(WxCombination::getId).collect(Collectors.toList());
                if(!combinationIds.contains(combinationId)){
                    map.put("data", "套餐错误，请重新扫码支付!");
                    map.put("code", 1);
                    return map;
                }
            }

            hour = Integer.parseInt(wxCombination.getHour()); // 获取设备开机一小时所需金额
		}else{
			hour = wxOrderMapper.getCombinationTime(hourMoney); // 获取设备开机一小时所需金额
		}
        int coMoney = 0;

        if (StringUtils.isNotEmpty(coupon)) {
            coMoney = (int) wxUserMapper.getCoMoney(coupon);// 优惠券对应金额数目
            if (type.equals("1") || type.equals("0")) {
                money = money - coMoney;
                money = money <= 0 ? 0 : money;
                wxUserMapper.setCoupon(wxUserInfo.getId(), coupon);
            }
        }

		if (!hashPermission(wxUserInfo.getId(), money, Integer.parseInt(type))) {
			map.put("data", "余额不足,请充值");
			map.put("code", 1);

			return map;
		}

		//查询设备是否在线
//		YjEquipment yjEquipment = yjEquipmentMapper.findUniqueByProperty("number",equipment);
//		if(yjEquipment== null || yjEquipment.getType().equals(1)){
//			map.put("data", "设备离线，请联系管理员！");
//			map.put("code", 2);
//			return map;
//		}

		// type=0 预购开机
		// type=1 余额开机
		// type=2 定单续费
		// type=3 充值
		// type=4 退款
		// type=5 开灯
		// type=-5 关灯

		// 开机业务只会传入0，1，2三个值
		// 开关机业务传入5或-5
		// 余额开机业务的逻辑修改：之前是默认开机一小时，现在调整为最大可开机时长
		if (type.equals("1")) {
			// int isUseCoupon=0;//是否使用代金券
			// Integer i = 60;//初始化为60分钟
			// 前台判断余额不足以开机一小时，则显示余额不足
			// money=Double.valueOf(equipmentMoney);

			// 下单金额/每小时所需金额 * 60 = 定单时长（分钟）
			// 计算订单时长，用总额，而不是去除优惠券的金额
			Integer orderLongTime = hour * MINUTES_OF_HOUR;

			wxOrderMapper.addOrder(orderNumber, wxUserInfo.getId(), name, type, text, String.valueOf(money), "0",
					equipment, orderLongTime,
					new Date(),new Timestamp(System.currentTimeMillis() + (MILLS_OF_SECOND * SECONDS_OF_MINUTE * orderLongTime)),
					1.0d, coMoney + "");

			// 设置定单状态为 未开始
			wxOrderMapper.setOrder(orderNumber, "", 1, "", "");

			// 不管是否使用代金券，如果最终money值大于0，这部分则为用户需要支付的费用
			if (money > 0) {
				wxUserWalletService.setDelMoney(wxUserInfo.getId(), money,name,orderNumber);
				// 消费之后，奖励积分
				// 增加积分明细
				WxUserIntegrationRecord wxUserIntegrationRecords = new WxUserIntegrationRecord();
				WxUser user = new WxUser();
				user.setId(wxUserInfo.getId());
				wxUserIntegrationRecords.setUser(user);
				wxUserIntegrationRecords.setType(0);
				wxUserIntegrationRecords.setText("消费奖励");
				wxUserIntegrationRecords.setIntegration(String.valueOf(money.intValue()));
				wxUserIntegrationRecordMapper.insert(wxUserIntegrationRecords);

			}
			maps.put("time", String.valueOf(orderLongTime));
			maps.put("code", "0");
			maps.put("msg", "success");
			JSONObject jsonObject = new JSONObject();
			jsonObject.put("orderNumber", orderNumber);
			maps.put("data", jsonObject);
			wxOrderMapper.addCommand(equipment, orderNumber, JSONObject.fromObject(maps).toString());

			// 开机(余额开机或预购开机)的同时开灯，此时记录到订单里，可回溯
			// 目前开关灯业务都是免费功能，时间默认为0，表示不受限制,金额也为0
			String lightStatusOrderNumber = Achieve.getUUIDString();
			wxOrderMapper.addOrder(lightStatusOrderNumber, wxUserInfo.getId(), "开灯", "5", "开机时开灯,开机订单号:" + orderNumber,
					"0", "0", equipment, 0,new Date(), new Timestamp(System.currentTimeMillis()), 0.0, "0");
			// 将订单状态设置到已结束
			wxOrderMapper.setOrder(lightStatusOrderNumber, "", 4, "", "");
			yjEquipmentMapper.setLightStatus(equipment, 5);// 设置设备开关灯状态,5为关灯状态
		} else if (type.equals("0")) {
			//检测前5分钟是否下单
//			List<WxOrder> yxOrderList = wxOrderMapper.getOrderByStatus(equipment,2);
			Date time = new Date();
//			if(yxOrderList.size() > 0){
//				time = yxOrderList.get(0).getEndTime();
//			}


			Integer i = hour * MINUTES_OF_HOUR; // 传入的money最大可开机小时数*60
			// number=number==null?equipment:number;
			// Double mone=wxOrderMapper.getEquipmentMoney(equipment);

			wxOrderMapper.addOrder(orderNumber, wxUserInfo.getId(), name, type, text, String.valueOf(money), "0",
					equipment, i,time, new Timestamp(time.getTime() + (MILLS_OF_SECOND * SECONDS_OF_MINUTE * i)),
					0.0, coMoney + "");

			wxOrderMapper.setOrder(orderNumber, "", 1, "", "");
			if (money > 0) {
				wxUserWalletService.setDelMoney(wxUserInfo.getId(), money,name,orderNumber);
				// 消费之后，奖励积分

				// 增加积分明细
				WxUserIntegrationRecord wxUserIntegrationRecords = new WxUserIntegrationRecord();
				WxUser user = new WxUser();
				user.setId(wxUserInfo.getId());
				wxUserIntegrationRecords.setUser(user);
				wxUserIntegrationRecords.setType(0);
				wxUserIntegrationRecords.setText("消费奖励");
				wxUserIntegrationRecords.setTime(new Date());
				wxUserIntegrationRecords.setIntegration(String.valueOf(money.intValue()));
				wxUserIntegrationRecordMapper.insert(wxUserIntegrationRecords);
			}

			maps.put("time", String.valueOf(i));

			maps.put("code", "0");
			maps.put("msg", "success");

			JSONObject jsonObject = new JSONObject();
			jsonObject.put("orderNumber", orderNumber);
			maps.put("data", jsonObject);
			wxOrderMapper.addCommand(equipment, orderNumber, JSONObject.fromObject(maps).toString());

			// 开机(余额开机或预购开机)的同时开灯，此时记录到订单里，可回溯
			// 目前开关灯业务都是免费功能，时间默认为0，表示不受限制,金额也为0
			String lightStatusOrderNumber = Achieve.getUUIDString();
			wxOrderMapper.addOrder(lightStatusOrderNumber, wxUserInfo.getId(), "开灯", "5", "开机时开灯,开机订单号:" + orderNumber,
					"0", "0", equipment, 0,new Date(), new Timestamp(System.currentTimeMillis()), 0.0, "0");
			// 将订单状态设置到已结束
			wxOrderMapper.setOrder(lightStatusOrderNumber, "", 4, "", "");
			yjEquipmentMapper.setLightStatus(equipment, 5);// 设置设备开关灯状态,5为关灯状态
		} else if (type.equals("2")) {
			Integer i = hour * MINUTES_OF_HOUR;

			// 续费
			// 上个订单
			// 续费逻辑：1.获取待续费的定单，2.获取endtime，3.endtime+续费时长=新的endtime，4.下单，5.将续费定单置为结束状态，6.更新原订单的endtime和money等信息
			WxOrder numberOrder = wxOrderMapper.getOrder(number);
			Date end = numberOrder.getEndTime();
			equipment = numberOrder.getEquipment().getId();
			Timestamp endTime = new Timestamp(end.getTime() + (MILLS_OF_SECOND * SECONDS_OF_MINUTE * i));
			double equipmentMoney = wxOrderMapper.getEquipmentMoney(equipment);
			wxOrderMapper.addOrder(orderNumber, wxUserInfo.getId(), name, type, text, String.valueOf(money), "0",
					equipment, i,new Date(), endTime, equipmentMoney, coMoney + "");
			// 将续费的订单设为4（过期），小程序端不展现续费订单。
			wxOrderMapper.setOrder(orderNumber, equipment, 4, "", "");
			//扣减余额 消费之后，奖励积分
			wxUserWalletService.setDelMoney(wxUserInfo.getId(), money,name,orderNumber);

			// 增加积分明细
			WxUserIntegrationRecord wxUserIntegrationRecords = new WxUserIntegrationRecord();
			WxUser user = new WxUser();
			user.setId(wxUserInfo.getId());
			wxUserIntegrationRecords.setUser(user);
			wxUserIntegrationRecords.setType(0);
			wxUserIntegrationRecords.setText("消费奖励");
			wxUserIntegrationRecords.setIntegration(String.valueOf(money.intValue()));
			wxUserIntegrationRecordMapper.insert(wxUserIntegrationRecords);

			maps.put("time", String.valueOf(i));
			// 将结束时间更新为endtime，订单金额更新为续费后的金额
			//wxOrderMapper.setEndOrderTime(endTime, i, number, Double.valueOf(money));
			maps.put("code", "0");
			maps.put("msg", "success");
			JSONObject jsonObject = new JSONObject();
			jsonObject.put("orderNumber", orderNumber);
			maps.put("data", jsonObject);
			wxOrderMapper.addCommand(equipment, orderNumber, JSONObject.fromObject(maps).toString());
			// 订单续费不用处理开灯，只要保持当前灯光状态即可

		} else if (type.equals("5") || type.equals("-5")) {
			// 目前开关灯业务都是免费功能，时间默认为0，表示不受限制,金额也为0
			wxOrderMapper.addOrder(orderNumber, wxUserInfo.getId(), name, type, text, "0", "0", equipment, 0,
					new Date(),new Timestamp(System.currentTimeMillis()), 0.0, "0");
			wxOrderMapper.setOrder(orderNumber, "", 1, "", "");

			// 消息格式类似：
			// 开灯{"msg":"success","code":"0","data":{"orderNumber":"8f19006ed9094013b1caa1f4e29d3061",type:"5"},"time":"0"}
			// 关灯{"msg":"success","code":"0","data":{"orderNumber":"8f19006ed9094013b1caa1f4e29d3061",type:"-5"},"time":"0"}
			// 经与硬件确认,设备内存太小消息中，加了json很容易溢出，故type字段尽量放在靠前的位置，如下：
			// {"msg":"success","code":"0","data":{type:"-5","orderNumber":"8f19006ed9094013b1caa1f4e29d3061"},"time":"0"}
			maps.put("time", "0");
			maps.put("code", "0");
			maps.put("msg", "success");
			// 通过LinkedHashMap保证json传中，type字段在前面
			Map<String, Object> dataObj = new LinkedHashMap<String, Object>();
			dataObj.put("type", type);
			dataObj.put("orderNumber", orderNumber);
			maps.put("data", JSONObject.fromObject(dataObj));
			wxOrderMapper.addCommand(equipment, orderNumber, JSONObject.fromObject(maps).toString());
		} else {
			// 后续更多可能的定单类型
		}

		map.put("data", orderNumber);
		map.put("code", 0);

		return map;
	}

	/**
	 *
	 * @author ljl
	 * @data 2018年3月16日
	 * @description 判断是否资格下单，如是否余额充足
	 * @param userId
	 * @param serviceMoney
	 *            订单金额
	 * @param serviceType
	 *            订单类型
	 * @param coupon
	 *            代金券金额
	 * @return
	 */
	public boolean hashPermission(String userId, double orderMoney, int orderType) {
		if (orderType == 1 || orderType == 0 || orderType == 2) {
			return (wxOrderMapper.getMoney(Double.valueOf(orderMoney), userId) > 0);
		}
		return true;
	}


}
